'''
Created on Apr 19, 2012

@author: root
'''

from Base import Base
import threading
#import time


class Filesystem(Base):
    
    '''
    Class Filesystem
    Init:  
        Users[] Array of Users for the Cluster
        Nodes[] Array of Nodes in the Cluster
    '''
    
    Users = []
    Nodes = [] 
    Disks = []
    mounts = []
    clusterDiskInfo = []
    clusterUserInfo = []
    mountPoint = ""
    dataDir = ""
    #returnQueue = Queue.Queue()

            
    def install(self):
        
        '''
        Method:  Install
        Purpose: Create Filesystems on Identified Devices
        Input:  
        '''
        
        self.LogInfo("Filesystem Creation Starting...")
        print "    * Creating Filesystems"
        threadCount = 0
        Threads = []
        for node in self.Nodes:
            for disk in node.Disks:
                mkfsCMD = str(self.installSudo) + "/sbin/mkfs -t " + str(disk.fsType) + " " + str(disk.deviceName)
                Threads.append(threading.Thread(target=self.SSHExec,args=(mkfsCMD,node.hostName,self.installUser,self.installPW,True)))
                Threads[threadCount].daemon=True
                Threads[threadCount].start()
                threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
           
            if (status == 0):
                #index = str(results).find("meta-data=")
                header = len("meta-data=")
             
                device = str(results[0][header:header+15]).strip()
                self.LogInfo("Filesystem Creation : "+str(hostName)+" : "+device)
                print "        * "+ str(hostName) + " : "+ str(disk.fsType).upper() + " Filesystem created on "+ device
            
        self.returnQueue.queue.clear()
        verifyStatus  = self.__Verify()
        return verifyStatus       
    
   

    def __Verify(self):
        
        '''
        Method: Verify
        
        Verifies that each device presented to the cluster has a valid
        Filesystem on it,
        
        Return 0 True, 1 False
        '''
        verifyStatus = 0
        status = 0
        clusterStatus = 0
        threadCount = 0
        Threads = []
        diskData = []
        self.LogInfo("Verifying Filesystem Status on Cluster Devices")
        print "    * Verifying Filesystem Creation"
        for node in self.Nodes:
            for disk in node.Disks:
                verifyCMD = str(self.installSudo) + "file -sL " + str(disk.deviceName)+" ; echo "+str(disk.fsType).upper()
                Threads.append(threading.Thread(target=self.SSHExec,args=(verifyCMD,node.hostName,self.installUser,self.installPW)))
                Threads[threadCount].daemon=True
                Threads[threadCount].start()     
                threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            device = str(results[0]).split(":")[0]
            if (status == 0) and str(results[1]).strip() in str(results[0]):
                self.LogInfo("Valid Filesystem Verified : "+str(hostName)+" : "+str(results))
                print "        * Valid "+ str(disk.fsType).upper() + " Filesystem verified on "+str(hostName)+" : "+str(device)
            else:
                self.LogError("No Valid Filesystem on "+ str(hostName)+" : "+str(results)+" ; Exiting")
                print "        * ERROR: No Valid " + str(disk.fsType).upper() + " Filesystem found on "+str(hostName)+" : "+str(device)
                verifyStatus = -1
        if (verifyStatus == 0):
            self.LogInfo("Verify FS Complete")
            for node in self.Nodes:
                for disk in node.Disks:
                    disk.fsStatus = 1
            
            
        return verifyStatus
    
    
    
#    def HostMounts(self):
#        for disk in node.Disks:
#            if (disk.fsStatus == 1):
#                diskCnt += 1
#                mountDir = str(self.mountPoint) + str(self.dataDir) + str(diskCnt)
#                mountCMD = str(self.installSudo) + "mkdir -p " + mountDir + ";mount -v -t " + str(disk.fsType) +" "+ str(disk.deviceName) + " " + str(mountDir)
#                Threads.append(threading.Thread(target=self.SSHExec,args=(mountCMD,node.hostName,self.installUser,self.installPW,True)))
#                Threads[threadCount].daemon=True
#                Threads[threadCount].start()
#                threadCount = threadCount + 1
      
    
    def Mount(self):
        mountStatus = 0
        threadCount = 0
        Threads = []
        
        self.LogInfo("Filesystem Mounting Process Started...")
        print "    * Mounting Filesystems to Cluster Nodes"
        for node in self.Nodes:
            diskCnt = 0
            for disk in node.Disks:
                if (disk.fsStatus == 1):
                    diskCnt += 1
                    mountDir = str(self.mountPoint) + str(self.dataDir) + str(diskCnt)
                    
                    ''' Sleep is a Patch Fix.  Long Term Fix needs to implement threads at host. instead of at disk.'''
                    
                    mountCMD = str(self.installSudo) + "sleep " + str(diskCnt/2) + ";" + str(self.installSudo) + "mkdir -p " + mountDir + ";"+str(self.installSudo) +"mount -v -t " + str(disk.fsType) +" "+ str(disk.deviceName) + " " + str(mountDir)
                    self.LogInfo(str(mountCMD))
                    Threads.append(threading.Thread(target=self.SSHExec,args=(mountCMD,node.hostName,self.installUser,self.installPW,True)))
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
                    
                
       
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            mountInfo = str(results).split(" ")
            if (status == 0):
                self.LogInfo(str(hostName) + ": Device " + mountInfo[0][2:] + " mounted at "  + mountInfo[2])
                print "        * "+ str(hostName) + ": Device " + mountInfo[0][2:] + " mounted at "  + mountInfo[2]
            elif ("is already mounted on" in str(results)):
                self.LogInfo(str(hostName) + ": Device " + mountInfo[0][2:] + " already mounted at "  + mountInfo[4])
                print "        * "+ str(hostName) + ": Device " + mountInfo[0][2:] + " already mounted at "  + mountInfo[4]

            else:
                self.LogError("Filesystem Could Not be Mounted "+ str(hostName)+" : "+str(results)+" ; Exiting")
                print "        * ERROR Filesystem Not Mounted : "+str(hostName)+" : "+str(results)

                mountStatus = -1
              
        if (mountStatus == -1):
            self.LogError("Not All Filesystems were not mounted; Exiting")
            #self.VerifyMounts()
            return -1
        else:
            self.LogInfo("Filesystem Mounting Process Complete")
            mountStatus = self.VerifyMounts()
            return mountStatus
            
            
            
    
    def VerifyMounts(self):
            
        threadCount = 0
        Threads = []
        print "    * Verifying Filesystem Mounts"
        for node in self.Nodes:
            verifymountCMD = str(self.installSudo) + "cat /proc/mounts"
            Threads.append(threading.Thread(target=self.SSHExec,args=(verifymountCMD,node.hostName,self.installUser,self.installPW)))
            Threads[threadCount].daemon=True
            Threads[threadCount].start()
            threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            for line in results:
                if (str(self.mountPoint) in line):
                    lineDetails = line.split()
                    mountDetails={}
                    mountDetails['hostName'] = hostName
                    mountDetails['device']=lineDetails[0]
                    mountDetails['path']=lineDetails[1]
                    self.mounts.append(mountDetails)
       
        ''' Now Take Mount details and use it to populate Object '''       
          
        
               
        for node in self.Nodes:
            for disk in node.Disks:
                for host in self.mounts:
                     if (str(node.hostName) == str(host['hostName'])):
                        if (str(disk.deviceName) in str(host['device'])):
                            disk.fsStatus = 1
                            disk.mountPath  = host['path']
                            disk.deviceName = host['device']
                            break
        

        
        ''' Verify all disk objects have a valid filesystem '''
        
        nodeCheck = 0
        for node in self.Nodes:
            fsCheck= 0
            for disk in node.Disks:  
                if (disk.fsStatus == 1):
                    fsCheck += 1
            if (fsCheck != len(node.Disks)):
                nodeCheck = -1
        if (nodeCheck ==0):
            self.LogInfo("All Nodes have Valid and Mounted Filesystems on all Devices")
            print "        * All Nodes have Valid and Mounted Filesystems on all Devices"
            return 0
        else:
            self.LogError("Not all nodes have valid and mounted Filesystems on all Devices")
            print "        * ERROR: Not All Nodes have Valid and Mounted Filesystems on all Devices"
            return -1
                    
        
                    
                             
    
    
    def CreateDataDirectories(self,projectName):
        createStatus = 0
        threadCount = 0
        Threads = []
        self.LogInfo("Creating Hadoop Data Directories on Cluster Nodes")
        print "    * Hadoop Data Directory Creation"
        for node in self.Nodes:
            diskCnt = 0
            for disk in node.Disks:
                if (disk.fsStatus == 1):
                    diskCnt += 1
                    createCMD = str(self.installSudo) + "mkdir -v -p " + disk.mountPath + "/" + str(projectName) + "/data"
                    self.LogInfo(createCMD)
                    Threads.append(threading.Thread(target=self.SSHExec,args=(createCMD,node.hostName,self.installUser,self.installPW)))
                    Threads[threadCount].daemon=True
                    Threads[threadCount].start()
                    threadCount = threadCount + 1
                
       
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
        
           
            
            if (status == 0):
               # if (len(results) == 0 ):
                    
                #dirName = (str(results).split(" ")[3])
                #dirName = str(dirName)[1:len(dirName)-5]
                
                self.LogInfo("Directory Created : "+str(hostName)+" : ")#+str(dirName))
                print "        * "+ "Directory Created : "+str(hostName)#+" : "+str(dirName)
            else:
                self.LogError("Directory Could Not be Created "+ str(hostName)+" : "+str(results)+" ; Exiting")
                createStatus = -1
        if (createStatus == -1):
            self.LogError("Not All Directories were created; Exiting")
            return -1
        else:
            self.LogInfo("All Directories Created at "+str(self.mountPoint))
            return 0
                  
    def BuildFSTab(self):
        ''' Create a string and append to remote fstab '''
        
        tabStatus = 0
        threadCount = 0
        Threads = [] 
        self.LogInfo("Building FSTAB on Cluster Nodes...")
        print "    * Building FSTAB on Cluster Nodes"

        for node in self.Nodes:
            for disk in node.Disks:
                
                tabSTR = str(disk.deviceName)+"        "+str(disk.mountPath)+"        "+str(disk.fsType)+" defaults    0 0"
                tabCMD = str(self.installSudo) + "cat /etc/fstab | grep " + str(disk.deviceName) + "; if [ $? -ne 0 ] ; then " + str(self.installSudo)+ "sh -c \"echo '"+tabSTR+"' >> /etc/fstab\" ; fi"
                Threads.append(threading.Thread(target=self.SSHExec,args=(tabCMD,node.hostName,self.installUser,self.installPW)))
                Threads[threadCount].daemon=True
                Threads[threadCount].start()     
                threadCount = threadCount + 1

        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            if (status == 0):
                self.LogInfo("FSTAB Entry:"+str(hostName)+":"+str(results))
            else:
                self.LogError(str(hostName)+" : "+str(results))
                tabStatus = -1
            
        if (tabStatus == 0):
            self.LogInfo("FSTAB Build Completed for all Cluster Nodes")
            print "        * FSTAB Built on all Cluster Nodes"
        else:
            self.LogError("FSTAB Build Failed ; Exiting")
            print "        * ERROR: FSTAB Build Failed"
        return tabStatus
                                             
          
          
                
    def __init__(self,Nodes,Users,mountPoint,dataDir):
        self.Users = Users
        self.Nodes = Nodes
        Base.__init__(self)
        self.SetUsers(self.Users)
        self.mountPoint = mountPoint
        self.dataDir = dataDir
        